package com.ylz.sjzx.sio.common.core.utils;

import cn.hutool.core.util.StrUtil;

import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * Desc :
 * Date : 2019/5/27
 */
public class DateUtil {

    /**
     * 时间格式 yyyy-MM-dd
     */
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String DATE_FORMAT_MM_DD_XIE = "MM/dd";

    public static final String DATE_FORMAT_YYYY_POINT_MM = "yyyy.MM";
    /**
     * 时间格式 yyyy年MM月dd日
     */
    public static final String DATE_FORMAT_YYYY_MM_DD_ZH = "yyyy年MM月dd日";
    /**
     * 时间格式 yyyyMMdd
     */
    public static final String DATE_FORMAT_YYYYMMDD = "yyyyMMdd";
    /**
     * 时间格式 yyyyMM
     */
    public static final String DATE_FORMAT_YYYYMM = "yyyyMM";
    /**
     * 时间格式 yyyy-MM
     */
    public static final String DATE_FORMAT_YYYY_MM = "yyyy-MM";

    /**
     * 时间格式 yyyy-MM-dd HH:mm:ss
     */
    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    /**
     * 时间格式 yyyy-MM-dd HH:mm
     */
    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    /**
     * 时间格式 yyyy
     */
    public static final String DATE_FORMAT_YYYY = "yyyy";

    private static final ParsePosition DEFAULT_POSITION = new ParsePosition(0);

    static int DATS = 24;
    @SuppressWarnings("rawtypes")
    private static ThreadLocal<Map<String, SimpleDateFormat>> threadLocal =
            new ThreadLocal<Map<String, SimpleDateFormat>>() {
                @Override
                protected synchronized Map<String, SimpleDateFormat> initialValue() {
                    Map<String, SimpleDateFormat> formatMap = new HashMap<>(2);
                    formatMap.put(DateUtil.DATE_FORMAT_YYYY_MM_DD, new SimpleDateFormat(DateUtil.DATE_FORMAT_YYYY_MM_DD));
                    formatMap.put(DateUtil.DATE_FORMAT_YYYY_MM_DD_HH_MM_SS, new SimpleDateFormat(
                            DateUtil.DATE_FORMAT_YYYY_MM_DD_HH_MM_SS));
                    return formatMap;
                }
            };

    /**
     * 线程优化
     *
     * @param format 格式
     * @return sf
     */
    private static SimpleDateFormat getDateFormat(String format) {
        return threadLocal.get().get(format);
    }

    /**
     * 线程优化
     *
     * @param textDate 日期str
     * @param format   格式
     * @return 日期
     */
    public static Date parse(String textDate, String format) {
        return getDateFormat(format).parse(textDate, DEFAULT_POSITION);
    }

    /**
     * @param date   日期
     * @param format 格式
     * @return 日期str
     */
    public static String format(Date date, String format) {
        if (date == null) {
            return null;
        }
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * @param millinos 日期
     * @param format   格式
     * @return 日期str
     */
    public static String format(long millinos, String format) {
        return new SimpleDateFormat(format).format(millinos);
    }


    /**
     * 区间合法性校验
     *
     * @param start  开始日期
     * @param end    结束日期
     * @param format 格式
     * @return 区间是否合法
     */
    private static Boolean dateRangeCheck(String start, String end, String format) {
        SimpleDateFormat sf = new SimpleDateFormat(format);

        if (StrUtil.isBlank(start) || StrUtil.isBlank(end)) {
            return true;
        }

        return !sf.parse(start, new ParsePosition(0)).after(sf.parse(end, new ParsePosition(0)));
    }

    /**
     * @param date   日期字符串
     * @param format format格式
     * @return 返回时间
     */
    public static Date getDate(String date, String format) {

        if (StrUtil.isBlank(date)) {
            return null;
        }
        return new SimpleDateFormat(format).parse(date, new ParsePosition(0));
    }

    /**
     * @param strDate 日期字符串
     * @param format  format格式
     * @return 获取传入日期的单天第一秒时间
     */
    public static Date getStartDayDate(String strDate, String format) {

        if (StrUtil.isBlank(strDate)) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(getDate(strDate, format));
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)
                , 0, 0, 0);
        return cal.getTime();
    }

    /**
     * date->str
     *
     * @param date   日期
     * @param format 格式
     * @return 日期str
     */
    public static String formateDate(Date date, String format) {

        if (date == null) {
            return null;
        }
        return new SimpleDateFormat(format).format(date);
    }

    //判断选择的日期是否是今天
    public static boolean isToday(long time) {
        return isThisTime(time, "yyyy-MM-dd");
    }

    //判断选择的日期是否是本周
    public static boolean isThisWeek(long time) {
        Calendar calendar = Calendar.getInstance();
        int currentWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        calendar.setTime(new Date(time));
        int paramWeek = calendar.get(Calendar.WEEK_OF_YEAR);
        if (paramWeek == currentWeek) {
            return true;
        }
        return false;
    }

    //判断选择的日期是否是本月
    public static boolean isThisMonth(long time) {
        return isThisTime(time, "yyyy-MM");
    }

    public static boolean isThisTime(long time, String pattern) {
        Date date = new Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String param = sdf.format(date);//参数时间
        String now = sdf.format(new Date());//当前时间
        if (param.equals(now)) {
            return true;
        }
        return false;
    }

    /***
     * 比较参数的值是否是昨天（是昨天返回 true）
     * @param oneTime
     * @return
     */
    public static boolean isYesterday(String oneTime) {
        //
        if (oneTime == null) {
            return false;
        }
        //获得昨天的值
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        String twoTime = sdf.format(calendar.getTime());
        //比较
        return oneTime.equals(twoTime);
    }

    /**
     * java 获取 获取某年某月 所有日期（yyyy-mm-dd格式字符串）
     *
     * @param year
     * @param month
     * @return
     */
    public static List<String> getMonthFullDay(int year, int month) {
        SimpleDateFormat dateFormatYYYYMMDD = new SimpleDateFormat("yyyy-MM-dd");
        List<String> fullDayList = new ArrayList<>(32);
        // 获得当前日期对象
        Calendar cal = Calendar.getInstance();
        cal.clear();// 清除信息
        cal.set(Calendar.YEAR, year);
        // 1月从0开始
        cal.set(Calendar.MONTH, month - 1);
        // 当月1号
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int count = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int j = 1; j <= count; j++) {
            fullDayList.add(dateFormatYYYYMMDD.format(cal.getTime()));
            cal.add(Calendar.DAY_OF_MONTH, 1);
        }
        return fullDayList;
    }

    /**
     * 某年某月的最后一天
     *
     * @param year
     * @param month
     * @return
     */
    public static String getLastDay(int year, int month) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month);
        cal.set(Calendar.DAY_OF_MONTH, 0); //关键！
        SimpleDateFormat dateFormatYYYYMMDD = new SimpleDateFormat("yyyy-MM-dd");
        return dateFormatYYYYMMDD.format(cal.getTime());
    }

    /**
     * 获取某年某月某日 是 星期几
     *
     * @param year
     * @param month
     * @param day
     * @return
     */
    public static String getDayOfWeek(int year, int month, int day) {
        //本地化
        Locale.setDefault(Locale.CHINA);
        String[] dayStringOfWeek = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, day);
        // Java中Calendar.DAY_OF_WEEK其实表示：一周中的第几天，所以他会受到第一天是 星期一 还是 星期日 的影响
        int d = cal.get(Calendar.DAY_OF_WEEK);
        return dayStringOfWeek[d - 1];
    }

    /**
     * 获取某年某月某日 是 星期几
     *
     * @return
     */
    public static String getWeek(Date date) {
        String[] weeks = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (week_index < 0) {
            week_index = 0;
        }
        return weeks[week_index];
    }

    /**
     * 获取最近几个月时间
     *
     * @param sourceDate
     * @param size
     * @return
     */
    public static List stepMonth(Date sourceDate, int size) {
        ArrayList<String> strings = new ArrayList<>();
        for (int i = size - 1; i >= 0; i--) {
            Calendar c = Calendar.getInstance();
            c.setTime(sourceDate);
            c.add(Calendar.MONTH, -i);
            Date time = c.getTime();
            String format = DateUtil
                    .format(time, DateUtil.DATE_FORMAT_YYYY_MM);
            strings.add(format);
        }

        return strings;
    }

    /**
     * 获取接下来的几个月
     *
     * @param date
     * @param dateType
     * @param month
     * @return
     */
    public static String addMonth(String date, String dateType, int month) {
        String nowDate = null;
        SimpleDateFormat format = new SimpleDateFormat(dateType);
        Date parse = null;
        try {
            parse = format.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(parse);
        calendar.add(Calendar.MONTH, month);
        nowDate = format.format(calendar.getTime());
        return nowDate;
    }

    /**
     * 通过日历类的Calendar.add方法第二个参数-1达到前一天日期的效果
     *
     * @return
     */
    public static String getYesterdayByCalendar(String dateFormat) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -1);
        Date time = calendar.getTime();
        String yesterday = new SimpleDateFormat(dateFormat).format(time);
        return yesterday;
    }

    /**
     * 通过日历类的Calendar.add方法第二个参数-1达到前一天日期的效果
     *
     * @return
     */
    public static Date getYesterdayByCalendar() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -1);
        Date time = calendar.getTime();
        return time;
    }

    /**
     * @param nowTime   当前时间
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     * @author sunran   判断当前时间在时间区间内
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }

        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    public static boolean compare(String time1, String time2) throws ParseException {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        //将字符串形式的时间转化为Date类型的时间
        Date a = sdf.parse(time1);
        Date b = sdf.parse(time2);
        //Date类的一个方法，如果a早于b返回true，否则返回false
        if (a.before(b)) {
            return true;
        } else {
            return false;
        }
    }

    public static boolean compare(String time1, String time2, String formate) throws ParseException {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf = new SimpleDateFormat(formate);
        //将字符串形式的时间转化为Date类型的时间
        Date a = sdf.parse(time1);
        Date b = sdf.parse(time2);
        //Date类的一个方法，如果a早于b返回true，否则返回false
        if (a.before(b)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * - （负数）————则推迟
     * <p>
     * -（正数）————则前几个小时
     *
     * @param startDate
     * @param hours
     * @return
     */
    public static String getPostponeTimesOradvanceTimes(String startDate, int hours) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sdf.parse(startDate));
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - hours);
        String endTime = sdf.format(calendar.getTime());
        return endTime;
    }

    /**
     * 计算两个日期时间相差几天,几小时,几分钟等
     *
     * @param start
     * @param end
     * @return
     */

    public static double getDatePoor(String start, String end) {
        //每天毫秒数
        double nd = 1000 * DATS * 60 * 60;
        //每小时毫秒数
        double nh = 1000 * 60 * 60;
        //每分钟毫秒数
        double nm = 1000 * 60;
        double diff = DateUtil
                .getDate(start, "HH:mm").getTime() - DateUtil.getDate(end, "HH:mm").getTime();
        // 计算差多少天
        double day = diff / nd;
        // 计算差多少小时
        double hour = diff % nd / nh;
        // 计算差多少分钟
        double min = diff % nd % nh / nm;
        return hour;

    }

    /**
     * 判断两个时间段是否有交集
     *
     * @param leftStartDate
     * @param leftEndDate
     * @param rightStartDate
     * @param rightEndDate
     * @return
     */
    public static boolean isOverlap(Date leftStartDate, Date leftEndDate, Date rightStartDate, Date rightEndDate) {
        return
                ((leftStartDate.getTime() >= rightStartDate.getTime())
                        && leftStartDate.getTime() < rightEndDate.getTime())
                        ||
                        ((leftStartDate.getTime() > rightStartDate.getTime())
                                && leftStartDate.getTime() <= rightEndDate.getTime())
                        ||
                        ((rightStartDate.getTime() >= leftStartDate.getTime())
                                && rightStartDate.getTime() < leftEndDate.getTime())
                        ||
                        ((rightStartDate.getTime() > leftStartDate.getTime())
                                && rightStartDate.getTime() <= leftEndDate.getTime());

    }

    /**
     * 计算两个日期时间相差几天
     *
     * @param start
     * @param end
     * @return
     */
    public static double compareDateDifferDay(String start, String end) {
        //每天毫秒数
        double nd = 1000 * DATS * 60 * 60;
        double diff = DateUtil.getDate(start, DATE_FORMAT_YYYY_MM_DD).getTime() -
                DateUtil.getDate(end, DATE_FORMAT_YYYY_MM_DD).getTime();
        // 计算差多少天
        double day = diff / nd;
        return day;
    }

}
